package domain.user ;

import java.util.HashSet;
import java.util.Set;

import persistence.Persistent;
import presentation.UIUser;
import util.HierarchicalSet;

/**
 * a user in the forum. this class is mainly responsible for managing privileges. for the moment, it is
 * immutable. users cannot be copied. they are single entities.
 *
 * users are not essentially persistent, yet they need some id external to the JVM's memory, so they are
 * persistent in the sense that their id persist outside of the JVM's memory. from the practical point of
 * view, members inherit from users, and java does not allow multiple inheritance.
 *
 * @author idan
 */
public class User extends Persistent implements UIUser
{
	private static final long serialVersionUID = -3402489345077449546L ;

	private HierarchicalSet<Privilege> privileges ;

	/**
	 * @param id id of this user.
	 * @param privileges privileges of this user.
	 * @post this.getPrivileges() = privileges
	 */
	public User(final long id, final Set<Privilege> privileges)
	{
		super(id) ;
		if (privileges != null)
		{
			this.privileges = new HierarchicalSet<Privilege>(privileges) ;
		}
		else
		{
			this.privileges = null ;
		}
	}

	/**
	 * @param privilege privilege to add.
	 * @post user is privileged by 'privilege'.
	 */
	public void addPrivilege(final Privilege privilege)
	{
		this.lockWrite() ;
		try
		{
			this.privileges.add(privilege) ;
		}
		finally
		{
			this.unlockWrite() ;
		}
	}

	/**
	 * @return privileges of this user.
	 */
	public final Set<Privilege> getPrivileges()
	{
		this.lockRead() ;
		try
		{
			return this.privileges ;
		}
		finally
		{
			this.unlockRead() ;
		}
	}

	/**
	 * @param privilege privilege to query for.
	 * @return whether the user has this privilege.
	 */
	public boolean isAllowed(final Privilege privilege)
	{
		this.lockRead() ;
		try
		{
			return this.getPrivileges().contains(privilege) ;
		}
		finally
		{
			this.unlockRead() ;
		}
	}

	/**
	 * @param privilege privilege to remove.
	 * @post user is not privileged by 'privilege'.
	 */
	public void removePrivilege(final Privilege privilege)
	{
		this.lockWrite() ;
		try
		{
			this.privileges.remove(privilege) ;
		}
		finally
		{
			this.unlockWrite() ;
		}
	}

	/**
	 * @return ordinals of the privileges.
	 */
	protected Set<Integer> getPrivilegesOrdinalVersion()
	{
		Set<Integer> result = new HashSet<Integer>() ;
		for (Privilege p: this.privileges)
		{
			result.add(p.ordinal()) ;
		}
		return result ;
	}

	/**
	 * @param privileges set of privileges to set for this user.
	 */
	protected void setPrivileges(final Set<Privilege> privileges)
	{
		this.privileges = new HierarchicalSet<Privilege>(privileges) ;
	}

	/**
	 * @param privileges privileges' ordinals.
	 */
	protected void setPrivilegesOrdinalVersion(final Set<Integer> privileges)
	{
		this.privileges = new HierarchicalSet<Privilege>() ;
		for (Integer i: privileges)
		{
			this.privileges.add(Privilege.values()[i]) ;
		}
	}

}
